///////////////////////////////////////////////////////////////////////////////////////////////////
// Illusion Ray Development Kit (IDK)           Copyright (c) 2010 ( dimitriy.martynenko@gmail.com )
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2010-05-22
// Updated : ...
// Licence : NEW BSD
// Info	   : IDK Engine
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include <IDK.hpp>
//
// TSceneNode
//

struct NodeDesc
{
	String name;
	Math::AABB aabbox;
	Math::Vector3 pos;
	Math::Quaternion rot;
	Math::Vector3 scale;

	NodeDesc(const String &name,
		const Math::AABB& aabbox = Math::AABB::Infinity,
		const Math::Vector3& pos = Math::Vector3::Zero,
		const Math::Quaternion& rot = Math::Quaternion::Identity,
		const Math::Vector3& scale = Math::Vector3::One) 
		: name(name),
		aabbox(aabbox),
		pos(pos),
		rot(rot), 
		scale(scale)
	{
	}
};

class TSceneNode : public TArray<IDK::Renderable>
{
	typedef TArray<IDK::Renderable> Base;
private:
	TSceneNode(void);
public:
	TSceneNode(const NodeDesc& desc);

	const String& GetName(void) const;
	void SetName(const String &name);
	void AddRenderable(IDK::Renderable obj);
	Array<IDK::Renderable> GetRenderables();
	bool IsVisible() const;
	void SetVisible(bool visible);
public:
	virtual bool Render(IDK::IRenderState& rndState);
	virtual void Rendered(IDK::IRenderState& rndState);
private:
	String mName;
	bool mClipped;
	bool mVisible;
public:
	//Scale
	void SetLocalScale(const Math::Vector3& scale);
	const Math::Vector3& GetLocalScale(void) const;
	const Math::Vector3& GetWorldScale(void) const;
	//Position
	void SetLocalPosition(const Math::Vector3& pos);
	const Math::Vector3& GetLocalPosition(void) const;
	const Math::Vector3& GetWorldPosition(void) const;
	//Rotation
	void SetLocalOrientation(const Math::Quaternion& rot);
	const Math::Quaternion& GetWorldOrientation(void) const;
	const Math::Quaternion& GetLocalOrientation(void) const;
	//Matrix
	const Math::Matrix44& GetLocalMatrix(void) const;
	const Math::Matrix44& GetWorldMatrix(void) const;
	//AABB
	const Math::AABB& GetOriginalAABBox(void) const;
	const Math::AABB& GetTransformAABBox(void) const;
	void SetOriginalAABBox(const Math::AABB& aabbox);
	//More Transform
	void Translate(const Math::Vector3& move);
	void Rotate(const Math::Quaternion& rot);
	void SetTransform(const Math::Quaternion& rot, const Math::Vector3& pos);
	//Update
	bool Update(ref<TSceneNode> parent, bool parentChanged);
private: 
	struct TransformChanged
	{
		enum Enum
		{
			NeedUpdate,
			ChangedPosition,
			ChangedOrientation,
			ChangedScale
		};
	};
	Math::Vector3 mLocalScale;
	Math::Vector3 mLocalPosition;
	Math::Quaternion mLocalOrientation;
	Math::Matrix44 mLocalMatrix;

	Math::Vector3 mWorldScale;
	Math::Vector3 mWorldPosition;
	Math::Quaternion mWorldOrientation;
	Math::Matrix44 mWorldMatrix;

	Math::AABB mOrigAABB;
	Math::AABB mTransformAABB;
	Set<TransformChanged::Enum> mTransformChanged;
};

typedef ref<TSceneNode> SceneNode;